home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / emerald / emrldsys.lha / Kernel / Em / hotsUpDown.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-17  |  16.8 KB  |  512 lines

  1.  
  2. /*
  3.  * $Header:   ~eden/Kernel/Em/hotsUpDown.c  Revision 1.0  85/07/08 eric Exp$
  4.  *
  5.  * FUNCTION:    This module contains routines for managing HOTS table
  6.  *        entries in the presence "unexpected" occurences such
  7.  *        as node death, transmission failures and arrival of
  8.  *        messages from previously unknown nodes.  Handlers for these
  9.  *        circumstances are defined as "upcall" routines which
  10.  *        all called from the lower level MM routines which actually
  11.  *        detect occurrence of the event.  This code is derived from
  12.  *        the old DataStructs/initHots.c
  13.  *
  14.  * EXPORTS:    InitHOTS(): Master initialization code for HOTS/MM protocol.
  15.  *        AddHOTS() : Insert newly alive node in HOTS table and
  16.  *                initialize protocol fields.
  17.  *        ChangeHOTS(): Change a known node from one state to another
  18.  *                  with attendant port/protocol cleanup.
  19.  *
  20.  * FIXME:    This module should know nothing about the VOIT, in
  21.  *        particular the fakey VOIT entries for nodes.  Unfortunately
  22.  *        the death detection routines and KMD stuff make this
  23.  *        a difficult bit of surgery without restructuring a lot
  24.  *        of other code as well.
  25.  *
  26.  * $Log:$
  27.  * Revision 1.0  85/06/11  12:16:27  oystr
  28.  * First release of this code in its current incarnation.  Following
  29.  * comments relate to the old file structure.
  30.  *
  31.  * Revision 3.7  85/03/11  13:38:21  eric
  32.  * Changed AddHOTS and ChangeHOTS to have more uniform semantics.
  33.  * Both now ensure proper cleanup when a local node dies.
  34.  *
  35.  * Revision 3.6  84/11/19  13:38:21  schwartz
  36.  * Added fServiceName parameter to initHots() so that other Service Ports
  37.  * than EDENKERNELSERVICEPORT could be used (EFTSERVICEPORT in particular)
  38.  *
  39.  * Revision 3.5  84/09/28 13:42:31  schwartz
  40.  * Changed DeclareDead() to call MMRemoteNodeDeath() after ChangeHOTS()
  41.  * to clean up protocol fields of Dead node.
  42.  *
  43.  * Revision 3.4  84/09/25 14:00:12  schwartz
  44.  * Changed ChangeHOTS() so that it uses DebugLevel 2 to print out the
  45.  * EtherAddr of the changed node (it used to always be printed).
  46.  *
  47.  * Revision 3.3  84/08/20 14:18:32  schwartz
  48.  * Made InitHOTS() return the status from its call to MMInitMsgModule.
  49.  *
  50.  * Revision 3.2  84/08/07 11:54:08  schwartz
  51.  * Split InitHOTS() into InitHOTS() and BootKernel() so that these functions
  52.  * can be used separately (e.g. the broadcast process needs only InitHOTS).
  53.  * Made AddHOTS() global; moved InitNextHOTS() to hotsTypes.h.
  54.  *
  55.  * Revision 3.1  84/07/25 02:47:08  schwartz
  56.  * Minor changes to accommodate EFT's new usage of the MM
  57.  *
  58.  * Revision 3.0  84/07/03 23:50:08  schwartz
  59.  * Changes to accommodate use of Unix 4.2 sockets for network communication.
  60.  *
  61.  * Revision 2.2  84/06/20 20:14:08  schwartz
  62.  * Added routines DeclareDead (formerly called MMDeclareDead; used
  63.  * to reside in ../MsgOps/msgCode.c) and BigRetransCountHandler, to handle
  64.  * big retransmission count errors (in order to keep this procedural 
  65.  * information encapsulated in the higher layer protocols, rather than in
  66.  * the low level message module)
  67.  *
  68.  * Revision 2.1  84/02/16  22:14:08  oystr
  69.  * Version 2 baseline.
  70.  * 
  71.  * Revision 1.7  84/02/16  15:23:54  eric
  72.  * Minor changes caused by new Message Module:
  73.  * Mostly new initialization routines inserted.
  74.  * 
  75.  * Revision 1.1  83/05/04  07:03:52  jim
  76.  * Initial revision
  77.  * 
  78.  */
  79.  
  80. #ifdef RCSID
  81. static char rcsid[] = "$Header$";
  82. #endif
  83.  
  84. #include <stdio.h>
  85.  
  86. #include "Kernel/h/system.h"
  87. #include "Kernel/h/stdTypes.h"
  88. #include "Kernel/h/mmCodes.h"
  89. #include "Kernel/h/errMsgs.h"
  90. #include "Kernel/h/mmTypes.h"
  91. #include "Kernel/h/mmMsgDefs.h"
  92. #include "Kernel/h/mmMsgTypes.h"
  93. #include "Kernel/h/kBootCodes.h"
  94. #include "Kernel/h/kEvents.h"
  95. #include "Kernel/h/dstCodes.h"
  96. #include "Kernel/h/hotsTypes.h"
  97. #include "Kernel/h/kBootTypes.h"
  98. #include "Kernel/h/kmdTypes.h"
  99.  
  100. extern KKStatus HOTSSearchPtr();
  101. extern time_t   nodeIncarnationId; /* imported from main.c */
  102. extern void     KillImposter();
  103. extern void     ScheduleBootReply();
  104. extern void     NodeStateChanged();
  105.  
  106.  
  107. /* Forward */
  108. void AddHOTS(), ChangeHOTS();
  109.  
  110. /*###*/
  111.  
  112. static int Cleanup[5][5] = {
  113.         /* Dead    */   { 0, 0, 0, 0, 0},
  114.         /* Alive   */   { 1, 0, 0, 0, 0},
  115.         /* Deaf    */   { 1, 0, 0, 0, 0},
  116.         /* Dumb    */   { 1, 0, 0, 0, 0},
  117.         /* Booting */   { 1, 0, 0, 0, 0}
  118.     };
  119.  
  120. static char *NodeStatNames[] = {
  121.     "Dead", "Alive", "Deaf", "Dumb", "Booting",
  122. };
  123.  
  124.  
  125. /***********************************************************************/
  126. /*      Upcall handlers for MM:                                        */
  127. /*          DeclareDead             Declares a node dead.              */
  128. /*          BigRetransCountHandler  Too many retransmits for msg.      */
  129. /*          EdenPortDeathHandler    A port dies - check for host death.*/
  130. /*          NoHOTSEntryHandler      We missed its bootup.              */
  131. /*          CheckMsg                Checks every incoming msg.         */
  132. /***********************************************************************/
  133.  
  134. HResult DeclareDead(fLNN)
  135. NodeNum fLNN;
  136. /* Scheduled by BigRetransCountHandler when an excessive number of
  137.    retransmits is reached for a node or when an Edenport has died.
  138.    Checks to see if the node is still Deaf and if so cleansup. */
  139. {
  140.     HOTSRecord *fHOTS;
  141.  
  142.     if (!mSUCCESS(HOTSSearchPtr(fLNN, &fHOTS) ) ) return; /* Entry deleted.*/
  143.  
  144.     if (fHOTS->NodeStat == Deaf) {
  145.     /* The node has died and the state set to deaf.
  146.        Now do the cleanup. */
  147.     ErrMsg("DeclareDead: LNN = %d, incarnation %.15s\n", fLNN,
  148.             4+ctime(&fHOTS->NodeIncarnationId));
  149.     ChangeHOTS(fHOTS->LNN, Dead);
  150.     } /* else other action (e.g., reboot) caused cleanup action. */
  151. }
  152.  
  153. KKStatus BigRetransCountHandler(fHOTSRec)
  154. HOTSRecord *fHOTSRec;
  155. {
  156.     ErrMsg( ">>> Declaring node %d Deaf\n", fHOTSRec->LNN);
  157.     /* The cleanup should be done by a scheduled tasks as the caller of
  158.        this routine may still hold pointers to the HOTS stuff. */
  159.     HoldSigs();
  160.     fHOTSRec->NodeStat = Deaf;
  161.     QueueTask( (HandlerPtr)DeclareDead, (char *)fHOTSRec->LNN);
  162.     ReleaseSigs();
  163.     return( MMSS_Success);
  164. }
  165.  
  166. KKStatus EdenPortDeathHandler()
  167. {
  168.     ErrMsg("EdenPortDeathHandler not supported\n");
  169. }
  170.  
  171.  
  172. KKStatus NoHOTSEntryHandler()
  173. /* MessagePtr fMsg; */
  174. /* Check the message to see if it is a first flow-controlled
  175.    message and if so change his state. */
  176. {
  177.     ErrMsg("NoHOTSEntryHandler called - should not happen!\n");
  178.     return(MMSF_BadConfig);
  179. };
  180.  
  181.  
  182. KKStatus CheckMsgSrc(fMsg, fHOTS)
  183. MessagePtr fMsg;
  184. HOTSRecord **fHOTS;
  185. /* Verify that the msg source is actually up and return a pointer to the
  186.    HOTS table entry for the node */
  187. {
  188.     KKStatus        kstat;
  189.     EtherNetAddress nodeAddr;
  190.     register MessageHeaderPtr hdr = &fMsg->MsgHdr;
  191.  
  192.     kstat = HOTSSearchPtr(hdr->MsgSrc, fHOTS);
  193.     if (!mSUCCESS(kstat)) {
  194.     if (kstat == DSTF_HOTSSearchNoEntry) {
  195.         /* Well, then create an entry */
  196.         KMDTrace("HOTSUpDown", 5,
  197.         "CheckMsgSrc: Inserting new node into HOTS, LNN %d\n",
  198.         hdr->MsgSrc);
  199.         nodeAddr = MMLocalEtherNet;
  200.         nodeAddr.sin_port = hdr->SrcSinPort;
  201.         nodeAddr.sin_addr = hdr->SrcSinAddr;
  202.         AddHOTS(nodeAddr, hdr->MsgSrc, IsActiveNode, Booting,
  203.             hdr->SrcIncarnationId);
  204.         /* Must look it up again since AddHOTS now has added it */
  205.         return (HOTSSearchPtr(hdr->MsgSrc, fHOTS));
  206.     } else {
  207.         /* Some serious error */
  208.         CantDoIt("CheckMsgSrc ", kstat);
  209.         return(kstat);
  210.     };
  211.     }
  212.     /* Now check incarnation */
  213.     if ((*fHOTS)->NodeIncarnationId == hdr->SrcIncarnationId) {
  214.     /* Rejoice, we know it */
  215.     return(MMSS_Success);
  216.     };
  217.     /* Problems:  Incarnation Ids do not match */
  218.     /* First do a duplicate node detection */
  219.     if (hdr->MsgSrc == GetLNN()) {
  220.     /* Ups, this guy is impersonating us -- let the newest guy win. */
  221.      if (nodeIncarnationId < hdr->SrcIncarnationId) {
  222.          /* He is newer - so let him continue */
  223.         ErrMsg("**** Duplicate LNN %d of %.15s at %s\n",
  224.         hdr->MsgSrc, 4+ctime(&hdr->SrcIncarnationId),
  225.         mGetHostName((EtherNetAddress *) &hdr->SrcSinAddr));
  226.         ErrMsg("**** Aborting this incarnation %.15s\n",
  227.         4+ctime(&nodeIncarnationId));
  228.         abort();
  229.      }
  230.      /* OK, so we are newer, send him a msg telling him to croak */
  231.      /* Note, this is very tricky since we cannot send him a msg directly
  232.      since he is not in our HOTS!  Therefore use a broadcast (sigh)
  233.      which is not very efficient and not very reliable. */
  234.      KillImposter(fMsg);
  235.      return(MMSF_NodeDown);
  236.     } else if ((*fHOTS)->NodeIncarnationId < hdr->SrcIncarnationId) {
  237.     /* Fine, the old one is dead, merely add the new one to the
  238.     HOTS table */
  239.     {
  240.         KMDTrace("HOTSUpDown", 5, "CheckMsgSrc: LNN %2d incarnation %.15s has died. \n",
  241.         hdr->MsgSrc, 4+ctime(&(*fHOTS)->NodeIncarnationId));
  242.         KMDTrace("HOTSUpDown", 5, "Will be replaced by incarnation %.15s\n",
  243.         4+ctime(&hdr->SrcIncarnationId));
  244.         nodeAddr = MMLocalEtherNet;
  245.         nodeAddr.sin_port = hdr->SrcSinPort;
  246.         nodeAddr.sin_addr = hdr->SrcSinAddr;
  247.         AddHOTS(nodeAddr, hdr->MsgSrc, IsActiveNode, Alive,
  248.             hdr->SrcIncarnationId);
  249.     }
  250.     } else {
  251.     /* This is an old Msg; we know of a newer incarnation, so drop
  252.     the message */
  253.     KMDTrace("HOTSUpDown", 2, "Dropping old msg #%d from %d of %s\n",
  254.         hdr->MsgSeq, hdr->MsgSrc, 4+ctime(&hdr->SrcIncarnationId));
  255.     return(MMSF_NodeDown);
  256.     }
  257.     return(MMSS_Success);
  258. }
  259.  
  260. /****************************************************************
  261.  *     Snapshots to modify Dead/Alive status of nodes.        *
  262.  ****************************************************************/
  263.  
  264. void PullUp(fLNN)
  265. int         fLNN;
  266. /* Force this node to think that the node specified by LNN is Alive. */
  267. {
  268.     HOTSRecord *hptmp;
  269.  
  270.     if ( mSUCCESS( HOTSSearchPtr(fLNN, &hptmp) ) ) {
  271.     /* The node is in the HOTS - use ChangeHOTS.  */
  272.     if ( (hptmp->NodeStat != Dead) || (hptmp->NodeStat != Dead) ) {
  273.         KMDPrint("Node %d not considered Dead - nothing changed.\n",
  274.         fLNN);
  275.         KMDPrint("  (use PullDown first)\n");
  276.     } else {
  277.         KMDPrint("Setting node %d to Alive.\n", fLNN);
  278.         ChangeHOTS(fLNN, Alive);
  279.     }
  280.     } else {
  281.     KMDPrint("Can't find node %d in HOTS.\n", fLNN);
  282.     }
  283. }
  284.  
  285. void PullDown(fLNN)
  286. int         fLNN;
  287. /* Force this node to think that the node specified by LNN is Dead
  288.    by calling ChangeHOTS */
  289. {
  290.     HOTSRecord *hptmp;
  291.  
  292.     if ( mSUCCESS( HOTSSearchPtr(fLNN, &hptmp) ) ) {
  293.     ChangeHOTS(fLNN, Dead);
  294.     KMDPrint("Node %d declared Dead.\n", fLNN);
  295.     } else {
  296.     KMDPrint("Can't find node %d in HOTS.\n", fLNN);
  297.     }
  298. }
  299.  
  300. /*
  301.  * General failure routine to save some space.  Never returns.
  302.  */
  303. /*VARARGS*/
  304. static CantDoIt( fString, fStatus )
  305. char    *fString;
  306. KKStatus fStatus;
  307. {
  308.   ErrMsg("Can't initialize %s: %08x....\n",fString,fStatus);
  309.   PutEdenMsg((int)fStatus, (FILE *)0, (char **)0);
  310. #ifdef BSD
  311.   system("Whatisup");
  312. #endif
  313.   exit(3);
  314. }
  315.  
  316. /*
  317.  *  Initializes the HOTS table stuff.
  318.  */
  319. void InitHOTS(fPort)
  320. int     fPort;
  321. {
  322.     KKStatus lStatus;
  323.  
  324.     KMDSetTrace(HOTSUpDown);
  325.  
  326.     /* Create an empty HOTS. */
  327.     lStatus = HOTSCreate();
  328.     if (!mSUCCESS(lStatus))
  329.     CantDoIt("HOTS");
  330.  
  331.     /* Asociate BigRetransCountHandler routine with event BIGRETRANSCOUNT */
  332.     lStatus = MMDefineUpcallHandler((HandlerPtr) BigRetransCountHandler,
  333.     BIGRETRANSCOUNT);
  334.     if (!mSUCCESS(lStatus))
  335.     CantDoIt("BigRetransCount Handler");
  336.  
  337.     /* Associate HOTSSearchPtr routine with event HOTSSEARCHPTR */
  338.     lStatus = MMDefineUpcallHandler((HandlerPtr) HOTSSearchPtr,
  339.     HOTSSEARCHPTR);
  340.     if (!mSUCCESS(lStatus))
  341.     CantDoIt("HOTSSearchPtr Handler");
  342.  
  343.     /* Associate HOTSCheckMsgSrc routine with event CHECKMSG */
  344.     lStatus = MMDefineUpcallHandler((HandlerPtr) CheckMsgSrc, CHECKMSG);
  345.     if (!mSUCCESS(lStatus))
  346.     CantDoIt("CheckMsgSrc Handler");
  347.  
  348.     /* Associate EdenPortDeathHandler routine with event EDENPORTDEATH */
  349.     lStatus = MMDefineUpcallHandler((HandlerPtr) EdenPortDeathHandler,
  350.     EDENPORTDEATH);
  351.     if (!mSUCCESS(lStatus))
  352.     CantDoIt("EdenPortDeath Handler");
  353.  
  354.     /* Associate NoHOTSEntryHandler routine with event NOHOTSENTRY */
  355.     lStatus = MMDefineUpcallHandler((HandlerPtr) NoHOTSEntryHandler,
  356.     NOHOTSENTRY);
  357.     if (!mSUCCESS(lStatus)) 
  358.     CantDoIt("NoHOTSEntry Handler");
  359.    
  360.    /* NOTE: these calls to define upcall handlers MUST be executed before
  361.       calling MMInitMsgModule for the first time, since MMInitMsgModule
  362.       makes use of these upcalls */
  363.  
  364.    /* Init the MM. */
  365.    lStatus = MMInitMsgModule(fPort);
  366.    if (!mSUCCESS(lStatus))
  367.     CantDoIt("MM");
  368.  
  369.    /* Define PullUp and PullDown snapshots for fudging the Dead/Alive
  370.       status of known nodes.
  371.       Note, these call should not be necessary after the boot protocol
  372.       has been fixed, Eric Jul, 1986-05-28 */
  373.  
  374.    KMDSetSnap(PullUp);
  375.    KMDSetSnap(PullDown);
  376.  
  377.    return;
  378. }
  379.  
  380. /***********************************************************************/
  381.  
  382. /*ARGSUSED*/
  383. void AddHOTS(fAddr, fLNN, fNodeType, fState, fIncarnationId)
  384. EtherNetAddress         fAddr;
  385. NodeNum                 fLNN;
  386. BitMap32                fNodeType;
  387. NodeStatus              fState;
  388. time_t                  fIncarnationId;
  389. {
  390.     KKStatus        lStatus;
  391.     HOTSRecord     *hotp, hot;
  392.     time_t          theTime      = time((time_t *) 0);
  393.         char            now[200];
  394.         
  395.         (void) strcpy(now, 4+ctime(&theTime));
  396.  
  397.     KMDTrace("HOTSUpDown", 5, "AddHOTS LNN %d of %.15s, state: %s\n",
  398.         fLNN, 4+ctime(&fIncarnationId), NodeStatNames[(int) fState]);
  399.     lStatus = HOTSSearchPtr(fLNN, &hotp);
  400.     /* We have to split into two cases depending on
  401.        whether we have heard from the node before. */
  402.     if (!mSUCCESS(lStatus)) {
  403.         KMDTrace("HOTSUpDown", 2, "AddHOTS: New LNN %d of %.15s\n", fLNN,
  404.         4+ctime(&fIncarnationId));
  405.         hot.LNN = fLNN;
  406.         hot.NodeStat = fState;
  407.         hot.NodeIsLocal = mEtherIsEqual(&fAddr, &MMLocalEtherNet);
  408.         hot.NodeNetPort = NULLEDENPORT;
  409.         hot.NodeIncarnationId = fIncarnationId;
  410.         hot.LastMsgTs = time((time_t *) 0);
  411.         hot.incomingLMQueue = (struct LMMsg *) NULL;
  412.         mEtherCopy(&fAddr, &(hot.EtherAddr));
  413.         lStatus = HOTSInsert(hot);
  414.         if (!mSUCCESS(lStatus)) {
  415.         ErrMsg(">>> AddHOTS:  HOTSInsert failure: 0x%08x\n",
  416.             lStatus);
  417.         return;
  418.         };
  419.         /* Now we unfortunately must look it up - HOTSInsert does not
  420.            give us the pointer back. (Stupid.) */
  421.         lStatus = HOTSSearchPtr(fLNN, &hotp);
  422.         if (!mSUCCESS(lStatus)) {
  423.         ErrMsg(">>> AddHOTS:  Bad HOTSSearchPtr status: 0x%08x\n",
  424.             lStatus);
  425.         return;
  426.         };
  427.         MMInitHOTSEntry(hotp);      /* Initialize protocol part. */
  428.  
  429.         KMDTrace("HOTSUpDown", 1,
  430.            "%-15.15s: AddHOTS LNN %d of %.15s @ %s\n",
  431.         now, (int) fLNN,
  432.         4+ctime(&hotp->NodeIncarnationId),
  433.         mGetHostName(&(hotp->EtherAddr)));
  434.         ScheduleBootReply(fLNN);
  435.             if (fState == Alive) NodeStateChanged(hotp);
  436.     } else {
  437.         /* Was already in HOTS, check incarnation id */
  438.         if (hotp->NodeIncarnationId < fIncarnationId) {
  439.         /* Kill off the old one. */
  440.         KMDTrace("HOTSUpDown", 3, "AddHOTS: killing LNN %d, incarnation %.15s\n",
  441.             fLNN, 4+ctime(&hotp->NodeIncarnationId));
  442.         ChangeHOTS(fLNN, Dead);
  443.         /* Now the previous incarnation has been purged. */
  444.         /* Start up a new one. */
  445.         hotp->NodeIsLocal = mEtherIsEqual(&fAddr, &MMLocalEtherNet);
  446.         hotp->NodeNetPort = NULLEDENPORT;
  447.         hotp->NodeIncarnationId = fIncarnationId;
  448.         mEtherCopy(&fAddr, &(hotp->EtherAddr));
  449.         MMInitHOTSEntry(hotp);      /* Initialize protocol part. */
  450.         ChangeHOTS(fLNN, fState);
  451.         } else {
  452.         /* Our HOTS table contains a reference to the right stuff */
  453.         ChangeHOTS(fLNN, fState);
  454.         }
  455.     } 
  456. }
  457.  
  458.         
  459. /**********************************************************************/
  460. /*      ChangeHOTS                                                    */
  461. /**********************************************************************/
  462. void ChangeHOTS(fLNN, fNewState)
  463. NodeNum fLNN;
  464. NodeStatus fNewState;
  465. {
  466.     KKStatus lStatus;
  467.     HOTSRecord *hotp;
  468.     NodeStatus oldstat;
  469.     time_t theTime = time((time_t *) 0);
  470.         char now[200];
  471.         
  472.         (void) strcpy(now, 4+ctime(&theTime));
  473.  
  474.         KMDTrace("HOTSUpDown", 6,"ChangeHOTS: LNN %d, newstate = %s\n", fLNN,
  475.         NodeStatNames[(int) fNewState]);
  476.  
  477.     lStatus = HOTSSearchPtr(fLNN, &hotp);
  478.     if (!mSUCCESS(lStatus)) {
  479.         ErrMsg("ChangeHOTS: Can't find LNN %04x in HOTS: 0x%08x...\n",
  480.         (int) fLNN, lStatus);
  481.         (void) PutEdenMsg((int)lStatus, (FILE *)0, (char **)0);
  482.         return;
  483.     }
  484.     oldstat = hotp->NodeStat;
  485.     KMDTrace("HOTSUpDown", 5, "  oldstate = %s, newstate = %s\n",
  486.         NodeStatNames[(int) oldstat], NodeStatNames[(int) fNewState]);
  487.     hotp->NodeStat = fNewState;
  488.     hotp->LastMsgTs = time((time_t *) 0);
  489.     KMDTrace("HOTSUpDown", 3,
  490.         "%-15.15s: ChangeHOTS LNN %d of %.15s @ %s from %s to %s\n",
  491.         now, (int) fLNN,
  492.         4+ctime(&hotp->NodeIncarnationId),
  493.         mGetHostName(&(hotp->EtherAddr)),
  494.         NodeStatNames[(int) oldstat], NodeStatNames[(int) fNewState]);
  495.     /*
  496.      * Cleanup any lines of communication between ourselves
  497.      * and the remote node.
  498.      */
  499.     if ( 1 == Cleanup[(int) oldstat][(int) fNewState] ) {
  500.         /* Null the port. */
  501.         hotp->NodeNetPort = NULLEDENPORT;
  502.         MMRemoteNodeDeath(hotp);
  503.     };
  504.     if ( (oldstat != fNewState) && ((fNewState == Booting)
  505.             || (fNewState == Alive))) {
  506.         ScheduleBootReply(fLNN);
  507.     };
  508.         
  509.         if ((oldstat != fNewState) && ((fNewState == Alive) ||
  510.             fNewState == Dead)) NodeStateChanged(hotp);
  511. }
  512.